/**
 * Copyright (C) 2010, 2011 Neofonie GmbH
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package eu.dicodeproject.analysis.restapi.controllers;

import eu.dicodeproject.analysis.restapi.HTablePoolHandler;
import twitter4j.internal.org.json.JSONException;
import twitter4j.internal.org.json.JSONObject;

import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.MediaType;

import org.apache.hadoop.hbase.client.HTableInterface;
import org.apache.hadoop.hbase.util.Bytes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

/**
 * @author jakob
 */
@Controller
public abstract class ControllerBase {

  protected static final Logger log = LoggerFactory.getLogger(ControllerBase.class);

  // TODO: define common schema for results:
  // - use a separate contentColumn for each meta-data type?
  // - use versions with fixed date instead of timestamps in key?
  // - or: use only one contentColumn for all results
  // - where goes the "query"?

  private HTablePoolHandler hTablePoolHandler;
  private Map<String, String> aliasTableNameMapping;
  protected byte[] columnFamily;
  protected byte[] fhgColumnFamily;
  protected byte[] columnQualifier;

  private int maximumResultLimit;
  private int jsonIndentFactor = 0;

  /**
   * Write JSON to response, including callback, and close the output stream.
   * @param callback arbitrary callback parameter
   * @param json the result
   * @param response object to write the result to
   * @throws java.io.IOException inherited from HBase Scan and HttpServletResponse.write
   * @throws twitter4j.internal.org.json.JSONException inherited from JSONObject constructor
   */
  protected void respond(String callback, JSONObject json, HttpServletResponse response)
      throws IOException, JSONException {

    String result = json.toString(jsonIndentFactor);

    // add JSONP prefix if callback is given
    if (callback != null) {
      StringBuffer sb = new StringBuffer(); // Spring Controllers should be thread-safe.  Don't use StringBuilder!
      sb.append("(").append(callback).append("(");
      sb.append(result);
      sb.append("))");
      result = sb.toString();
    }

    response.setContentType(MediaType.APPLICATION_JSON);
    response.setCharacterEncoding("UTF-8");
    OutputStream out = response.getOutputStream();

    out.write(Bytes.toBytes(result));
    out.flush();
    out.close();
  }

  protected HTableInterface getHTable(String tableName)  {
    return this.hTablePoolHandler.getHTable(tableName);
  }

  protected String getTableName(String source) {
    String tableName = this.aliasTableNameMapping.get(source);
    if (tableName == null) {
      Set<String> knownAliases = this.aliasTableNameMapping.keySet();
      throw new IllegalArgumentException("unknown source alias '" + source + "'; known aliases: " + knownAliases);
    }
    return tableName;
  }

  protected int getResultLimit(Integer userResultLimit) {
    if (userResultLimit == null || userResultLimit > this.maximumResultLimit) {
      return maximumResultLimit;
    }
    return userResultLimit;
  }

  @Autowired
  public void setHTablePoolHandler(HTablePoolHandler handler) {
    this.hTablePoolHandler = handler;
  }

  public void setAliasTableNameMapping(Map<String, String> aliasTableNameMapping) {
    this.aliasTableNameMapping = aliasTableNameMapping;
  }

  public void setColumnFamily(String columnFamily) {
    this.columnFamily = Bytes.toBytes(columnFamily);
  }
  
  public void setFhgColumnFamily(String fhgColumnFamily) {
    this.fhgColumnFamily = Bytes.toBytes(fhgColumnFamily);
  }

  public void setColumnQualifier(String columnQualifier) {
    this.columnQualifier = Bytes.toBytes(columnQualifier);
  }

  public void setMaximumResultLimit(int maximumResultLimit) {
    this.maximumResultLimit = maximumResultLimit;
  }

  public void setJsonIndentFactor(int jsonIndentFactor) {
    this.jsonIndentFactor = jsonIndentFactor;
  }

}
